package com.sdk.bigdata.utils;

import com.cronutils.model.CronType;
import com.cronutils.model.definition.CronDefinition;
import com.cronutils.model.definition.CronDefinitionBuilder;
import com.cronutils.parser.CronParser;
import com.sdk.bigdata.exceptions.DataConfigLoadException;
import com.sdk.bigdata.exceptions.PropertiesLoadException;
import com.sdk.bigdata.model.DataConfig;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class PropertiesUtil {

    private static final String propertiesName = "config.properties";
    private static Properties properties = new Properties();

    private static volatile DataConfig config;

    public static DataConfig getConfig() throws PropertiesLoadException {
        if (null == config) {
            synchronized (PropertiesUtil.class) {
                if (null == config) {
                    initConfig();
                }
            }
        }
        return config;
    }

    private static void initConfig() throws PropertiesLoadException {
        InputStream is;
        is = PropertiesUtil.class.getClassLoader().getResourceAsStream(propertiesName);
        try {
            if (null != is)
                properties.load(is);
        } catch (IOException e) {
            throw new PropertiesLoadException("config.properties文件加载失败: " + e.getMessage());
        } finally {
            try {
                if (null != is)
                    is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        //日志级别
        LoggerUtil.setLogLevel(properties.getProperty("LogLevel"));

        // 校验及初始化config
        DataConfig dataConsumerConfig = new DataConfig();
        if (properties.getProperty("Url") == null || properties.getProperty("Url").equals("")) {
            throw new PropertiesLoadException("property [Url] can't be empty");
        }
        dataConsumerConfig.setUrl(properties.getProperty("Url"));

        dataConsumerConfig.setTimezone((null == properties.getProperty("Timezone") || properties.getProperty("Timezone").equals("")) ?
                "Asia/Shanghai" : properties.getProperty("Timezone"));

        //目前只支持None
        String compression = properties.getProperty("Compression");
        if (!compression.toLowerCase().equals("none")) {
            System.out.println("暂时不支持压缩算法");
        }
        dataConsumerConfig.setCompression("none");

        // check timeout
        Long timeout;
        try {
            timeout = Long.valueOf(properties.getProperty("Timeout"));
        } catch (Exception e) {
            throw new PropertiesLoadException("property [Timeout] should > 0");
        }
        if (timeout <= 0) {
            throw new PropertiesLoadException("property [Timeout] should > 0");
        }
        dataConsumerConfig.setTimeout(timeout);

        // check maxSize
        Integer maxSize;
        try {
            maxSize = Integer.valueOf(properties.getProperty("MaxSize"));
        } catch (Exception e) {
            throw new PropertiesLoadException("property [MaxSize] should > 0");
        }
        if (maxSize <= 0) {
            throw new PropertiesLoadException("property [MaxSize] should > 0");
        }
        dataConsumerConfig.setMaxSize(maxSize);

        // check Secret
        String secret = properties.getProperty("Secret");
        if (null == secret || secret.equals(""))
            throw new PropertiesLoadException("property [Secret] can't be empty");
        dataConsumerConfig.setSecret(secret);

        // check maxConsumer
        Integer maxConsumer;
        try {
            maxConsumer = Integer.valueOf(properties.getProperty("MaxConsumer"));
        } catch (Exception e) {
            throw new PropertiesLoadException("property [MaxConsumer] should > 0");
        }
        if (maxConsumer <= 0) {
            throw new PropertiesLoadException("property [MaxConsumer] should > 0");
        }
        dataConsumerConfig.setMaxConsumer(maxConsumer);

        // check GameType
        String gameType = properties.getProperty("GameType").toUpperCase();
        if (checkGameType(gameType)) {
            throw new PropertiesLoadException("property [GameType] is invalid, Please choose " +
                    "[CAG,CCG,RPG,SLG,ACT,AVG,PUZ,MOBA,RAC,RTS,TBG,MSC,SPG]");
        }
        dataConsumerConfig.setGameType(gameType);

        // check gameId
        Integer gameId;
        try {
            String gameString = properties.getProperty("GameId");
            if (null == gameString || gameString.length() <= 0) {
                throw new PropertiesLoadException("property [GameId] can't <= 0");
            }
            gameId = Integer.valueOf(gameString);
        } catch (Exception e) {
            throw new PropertiesLoadException(e.getMessage());
        }
        dataConsumerConfig.setGameId(gameId);

        // check CronSpec
        String cronSpec = properties.getProperty("CronSpec");
        if (null == cronSpec || cronSpec.equals("")) { // 默认值
            cronSpec = "0/10 * * * * ?";
        } else {
            try {
                CronDefinition cronDefinition = CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ);
                CronParser parser = new CronParser(cronDefinition);
                parser.parse(cronSpec);
            } catch (Exception e) {
                throw new PropertiesLoadException("property [CronSpec] has error:" + e.getMessage());
            }
        }
        dataConsumerConfig.setCronSpec(cronSpec);

        Integer maxQueue;
        try {
            maxQueue = Integer.valueOf(properties.getProperty("MaxQueue"));
        } catch (Exception e) {
            throw new PropertiesLoadException("property [MaxQueue] should > 0");
        }
        if (maxQueue <= 0) {
            throw new PropertiesLoadException("property [MaxQueue] should > 0");
        }
        dataConsumerConfig.setMaxQueue(maxQueue);

        config = dataConsumerConfig;
    }

    public static void checkDataConfig(DataConfig config) throws DataConfigLoadException {
        // 设置日志级别
        LoggerUtil.setLogLevel(config.getLogLevel());
        if (config.getUrl() == null || config.getUrl().equals("")) {
            throw new DataConfigLoadException("property [Url] can't be empty");
        }
        if (null == config.getTimezone() || config.getTimezone().equals("")) {
            config.setTimezone("Asia/Shanghai");
        }
        Long timeout = config.getTimeout();
        if (timeout == null || timeout <= 0) {
            throw new DataConfigLoadException("property [Timeout] should > 0");
        }
        Integer maxSize = config.getMaxSize();
        if (maxSize == null || maxSize <= 0) {
            throw new DataConfigLoadException("property [maxSize] should > 0");
        }
        String secret = config.getSecret();
        if (null == secret || secret.equals("")) {
            throw new DataConfigLoadException("property [Secret] can't be empty");
        }

        Integer maxConsumer = config.getMaxConsumer();
        if (null == maxConsumer || maxConsumer <= 0) {
            throw new DataConfigLoadException("property [maxConsumer] should > 0");
        }

        String gameType = config.getGameType();
        if (checkGameType(gameType)) {
            throw new DataConfigLoadException("property [GameType] is invalid, Please choose " +
                    "[CAG,CCG,RPG,SLG,ACT,AVG,PUZ,MOBA,RAC,RTS,TBG,MSC,SPG]");
        }

        // check gameId
        Integer gameId = config.getGameId();
        if (null == gameId) {
            throw new DataConfigLoadException("property [GameId] can't be empty");
        }
        String gameString = gameId + "";
        if (gameString.length() <= 0) {
            throw new DataConfigLoadException("property [GameId] can't <= 0");
        }

        // check CronSpec
        String cronSpec = config.getCronSpec();
        if (null == cronSpec || cronSpec.equals("")) { // 默认值
            config.setCronSpec("0/10 * * * * ?");
        } else {
            try {
                CronDefinition cronDefinition = CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ);
                CronParser parser = new CronParser(cronDefinition);
                parser.parse(cronSpec);
            } catch (Exception e) {
                throw new DataConfigLoadException("property [CronSpec] has error:" + e.getMessage());
            }
        }

        Integer maxQueue = config.getMaxQueue();

        if (null == maxQueue || maxQueue <= 0) {
            throw new DataConfigLoadException("property [MaxQueue] should > 0");
        }

    }


    private static boolean checkGameType(String gameType) {
        switch (gameType) {
            case "CAG":
            case "CCG":
            case "RPG":
            case "SLG":
            case "ACT":
            case "AVG":
            case "PUZ":
            case "MOBA":
            case "RAC":
            case "RTS":
            case "TBG":
            case "MSC":
            case "SPG":
                return false;
            default:
                return true;
        }
    }
}
